/*
 *  client.c
 *  peertopeer
 *
 *  Created by jihed kamkoum on 09/05/10.
 *  Copyright 2010 ENSEIRB. All rights reserved.
 *
 */

#include "client.h"

return_t handler_KeyEvents(const char * events,binder * b){
	
	char message[NAMESIZE];
	//char * parametre;
	//recuperation du nom du message
	sscanf(events, "%s", message);
	if (strcmp(message, "connect") == 0) {
		// message de la form connect ip port
		char name[NAMESIZE],ip[NAMESIZE];
		int port;
		sscanf(events,"%s %s : %d",name,ip,&port);
		connect_program(ip,port,*b->ip,*b->port,b->csock,b->socketAccess);
		return RT_OK;
	} else if (strcmp(message, "list") == 0) {
		list(b->csock,events,b->semid,*b->listeFichiers,b->fileTableAccess);
		return RT_OK;
	} else if (strcmp(message, "traffic") == 0) {
		traffic(b->csock,events,b->semid);
		return RT_OK;
	} else if (strcmp(message, "set") == 0) {
		if((write(b->fdpipe1, events, (strlen(events)+1))==-1)){
			perror("write");
			exit(EXIT_FAILURE);
		}
		return RT_OK;
	} else if (strcmp(message, "upload") == 0) {
		if((write(b->fdpipe1, events, (strlen(events)+1))==-1)){
			perror("write");
			exit(EXIT_FAILURE);
		}
		return RT_OK;
	} else if (strcmp(message, "checksum") == 0) {
		checksum(events, b->csock,b->semid);
		return RT_OK;
	} else if (strcmp(message, "download") == 0) {
		pthread_mutex_lock(b->downloadTableAccess);
		afficher_listeDownload(*b->listeDownload);
		pthread_mutex_unlock(b->downloadTableAccess);
		return RT_OK;
	} else if (strcmp(message, "get") == 0) {
		get(b->csock,b->semid,*b->path,events,*b->listeDownload,b->downloadTableAccess);
		
		return RT_OK;
	}  else if (strcmp(message, "raw") == 0) {
		raw(events,b->csock,b->semid,*b->ip,*b->port,b->socketAccess);
		
		return RT_OK;
	}else if (strcmp(message, "info") == 0) {
		return RT_OK;
	} else if (strcmp(message, "neighbourhood") == 0) {
		neighbourhood(b->csock,events,b->semid);
		return RT_OK;
	}else if (strcmp(message, "help") == 0) {
		help();
		return RT_OK;
	}

	fprintf(stderr,"message non reconnu\n");
	return RT_ERR;
}
void f_thread_receiver(binder  *bi){
	printf("debut thread client %d\n",pthread_self());
	//retarder l'execution du thread pour que la priorite soit effective
	sleep(rand()%3);
	fd_set socks;
	struct timeval timeout;
	char recived[BUFSIZ];
	memset((char *) &recived, 0, sizeof(recived));
	int readsocks;
	int ret;
	while (1) {
		if (*bi->csock !=-1) {
			pthread_mutex_lock(bi->socketAccess);
			timeout.tv_sec = 1;
			timeout.tv_usec = 0;
			setnonblocking(*bi->csock);
			setnonblocking(bi->fdpipes0);

			FD_ZERO(&socks);
			FD_SET(*bi->csock,&socks);
			FD_SET(bi->fdpipes0,&socks);
			int highfd = 0;
			if (bi->fdpipes0 > *bi->csock) {
				highfd =bi->fdpipes0;
			}
			else {
				highfd =*bi->csock;
			}

			readsocks = select(highfd+1, &socks, (fd_set *) 0,(fd_set *) 0, &timeout);
			if (readsocks < 0) {
				perror("select");
				exit(EXIT_FAILURE);
			}
			else if (readsocks == 0) {
				//printf(".");
				fflush(stdout);
				pthread_mutex_unlock(bi->socketAccess);
				if((sched_yield()==-1)){
					perror("yield");
					sleep(1);
				}

			} else if (FD_ISSET(*bi->csock,&socks)) {
				//pthread_mutex_lock(bi->socketAccess);
				if((ret=recv(*bi->csock, recived, sizeof(recived), 0))==-1)
					perror("receive");
				else if (ret !=0) {

					char namecmd[NAMESIZE];
					sscanf(recived,"%s ",namecmd);
					if (strcmp(namecmd,"file")==0) {
						printf("%s\n",recived);
						char ip[TAILLE_IP];
						int taille;
						int port;
						char key[100];
						char file[100];
						sscanf(recived,"%s %s %s %d %s : %d",namecmd,file,key,&taille,ip,&port);
						file_p info;
						info = malloc(sizeof(file_t));
						info->name = malloc(BUFSIZ);
						strcpy(info->ip,ip);
						info->port_s = port;
						memset((char *)info->name, 0, BUFSIZ);
						info->key = malloc(100);
						strcpy((char *)info->name,file);
						strcpy((char *)info->key, key);
						info->size =taille;
						pthread_mutex_lock(bi->fileTableAccess);
						if (findElementByKey(*bi->listeFichiers,(u_char *)key)==NULL) {

							flist_insert(*bi->listeFichiers, info);

						}
						else {
							free(info);
						}
						pthread_mutex_unlock(bi->fileTableAccess);
					}
					else if(strcmp(namecmd,"neighbour")==0){
						printf("%s\n",recived);
						char ip[TAILLE_IP];
						int port;
						sscanf(recived,"%s %s : %d ",namecmd,ip,&port);
						client_t * cl = malloc(sizeof(client_t));
						strcpy(cl->ip,ip);
						cl->port_s = port;
						cl->socket = -1;
						cl->last_event = clock();
						cl->isclient = FAUX;
						cl->port_c = 0;
						pthread_mutex_lock(bi->clientTableAccess);
						if (checkClientExist(*bi->listeClients, cl)==0) {
							clientlist_insert(*bi->listeClients, cl);
						}
						else {
							free(cl);
						}

						pthread_mutex_unlock(bi->clientTableAccess);


					}
					else if(strcmp(namecmd,"end_neighbour")==0){
						pthread_mutex_lock(bi->neighbourhoodCondMutex);
						*bi->neighbourhoodbool = VRAI;
						pthread_mutex_unlock(bi->neighbourhoodCondMutex);
						pthread_cond_broadcast(bi->neighbourhoodCond);
					}
					else if(strcmp(namecmd,"end_file")==0){
						pthread_mutex_lock(bi->listCondMutex);
						*bi->listbool = VRAI;
						pthread_mutex_unlock(bi->listCondMutex);
						pthread_cond_broadcast(bi->listCond);
					}
					else if(strcmp(namecmd,"end_traffic")==0){
						pthread_mutex_lock(bi->trafficCondMutex);
						*bi->trafficbool = VRAI;
						pthread_mutex_unlock(bi->trafficCondMutex);
						pthread_cond_broadcast(bi->trafficCond);
					}
					else if(strcmp(namecmd,"redirect")==0){
						printf("%s\n",recived);
					}
					else if(strcmp(namecmd,"ready")==0){
						printf("%s\n",recived);
						char ip[TAILLE_IP];
						char key[100];
						int port;
						int delay;
						int debut,fin;
						sscanf(recived,"%s %s %d %s %d  TCP %d %d",namecmd,key,&delay,ip,&port,&debut,&fin);
						upload * up = malloc(sizeof(upload));
						strcpy((char *)up->key, key);
						strcpy(up->ip,ip);
						up->port = port;
						up->delay = delay;
						up->debut = debut;
						up->fin = fin;
						pthread_mutex_lock(bi->uploadTableAccess);
						if ((checkExistUpload(*bi->listeUpload,up))==0) {
							insererUpload(*bi->listeUpload,up);

						}
						else {
							free(up);
						}
						pthread_mutex_unlock(bi->uploadTableAccess);

					}
					else if(strcmp(namecmd,"checksum")==0){
						printf("%s\n",recived);
					}
					else if(strcmp(namecmd,"getting")==0){
						printf("%s\n",recived);
						download *down;
						int delay;
						int begin,end;
						down = malloc(sizeof(download));
						char name[NAMESIZE];
						char proto[8];
						bzero((char *)name, NAMESIZE);
						char key[100];
						bzero((char *)key, 100);
						sscanf(recived,"%s %s %d %s %d %s %d %d",name,down->key,&delay,down->ip,&(down->port),proto,&begin,&end);
						down->pourcentage = 0;
						down->size = end - begin +1;
						tget * arg = malloc(sizeof(tget));
						arg->down = down;
						arg->path = *bi->path;
						arg->semid = bi->semid;
						arg->delay = delay;
						arg->listeDownload = *bi->listeDownload;
						arg->downloadTableAccess = bi->downloadTableAccess;
						arg->begin = begin;
						arg->end = end;
						struct sembuf op;
								op.sem_num = 0; //Test si le thread est dispo
								op.sem_op = -1; //P()
								op.sem_flg = 0; //attente de l'operation
								if((semop(bi->semid, &op, 1)==0)){
									/*thread disponnible*/
									pthread_t threadget;
									/*creation du thread*/
									if((pthread_create(&threadget, NULL,(void *)f_thread_get,arg))==-1)
										printf("probleme pthread_create \n");
									else {
										changer_ordo_priorite(threadget, SCHED_RR, 5);
									}
								}
								else{
									perror("semop P()");
								}
					}
					else {
						printf("%s\n",recived);
					}

					pthread_mutex_unlock(bi->socketAccess);
					sched_yield();
					sleep(1);
				}
			}
			else if (FD_ISSET(bi->fdpipes0,&socks)) {
				char propage[80];
				//sleep(2);
				bzero((char *)propage, 80);
				if((read(bi->fdpipes0, propage, sizeof(propage))==-1)){
					perror("read");
					//exit(EXIT_FAILURE);
				}
				else if(strcmp(propage,"neighbourhood")==0){
					neighbourhood(bi->csock,"neighbourhood" ,bi->semid);
				}
				else if(strcmp(propage,"list")==0){
					list(bi->csock,"list" ,bi->semid,*bi->listeFichiers,bi->fileTableAccess);
				}
				else if(strcmp(propage,"traffic")==0){
					traffic(bi->csock,"traffic",bi->semid);
				}
				pthread_mutex_unlock(bi->socketAccess);

			}
		}
	}

}
